<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        li {
            list-style: none;
            line-height: 40px;
        }

        .title {
            line-height: 40px;
        }

        .list {
            overflow: hidden;
        }

        .list li {
            border: 1px dashed #333;
            text-indent: 10px;
            height: 40px;
        }

        .box {
            margin-top: 20px;
        }
    </style>
</head>

<body>
    <h3 id="title">模拟封装jquery</h3>
    <input class="inp" type="text">
    <div class="list">
        <li>li_01</li>
        <li>li_02</li>
        <li>li_03</li>
        <li>li_04</li>
        <li>li_05</li>
        <li>li_06</li>
        <li>li_07</li>
        <li>li_08</li>
        <li>li_09</li>
        <li>li_10</li>
    </div>
    <div class="box">
        <button class="setHtml">
            设置html
        </button>
        <button class="getHtml">
            获取html
        </button>
        <button class="hide">隐藏</button>
        <button class="show">显示</button>
        <button class="setWidth">
            设置宽度
        </button>
        <button class="getWidth">
            获取宽度
        </button>

        <button class="attr">attr</button>
        <button class="prop">prop</button>
        <button class="css">css</button>
        <button class="addClass">addClass</button>
        <button class="removeClass">removeClass</button>
        <button class="eq">eq</button>
        <button class="siblings">siblings</button>
        <button class="chain">链式操作</button>
    </div>
</body>
<script>
    // jquery  原生js封装的一个库,快速获取元素,操作元素  (dom的增删改查,事件,ajax,运动)

    // 构造函数 传入一个css选择器,返回对应的实例化对象    {eles:[]}
    function GetEle(selector) {
        // {}
        // this -> {}

        // 匹配的元素的集合
        this.eles = document.querySelectorAll(selector);

        // this.__proto__ = GetEle.prototype;
        // return this;   // {eles:[]}
    }

    // 遍历实例化对象中的集合 操作集合中的每一个元素
    GetEle.prototype.html = function (con) {
        // this ->指向调用此方法的实例化对象 {eles:[]}
        if (arguments.length >= 1) {  // 有参数
            // for (var i = 0; i < this.eles.length; i++) {
            //     var ele = this.eles[i];
            //     ele.innerHTML = con;
            // }

            // 实例化对象 均可以访问prototype上的方法
            this.each(function (ele) {
                ele.innerHTML = con;
            })
            return this;
        } else { //没有参数
            // 默认返回集合中的第一个(模拟jquery)
            return this.eles[0].innerHTML;
        }
    }
    GetEle.prototype.text = function (con) {
        if (arguments.length >= 1) {  // 有参数
            // for (var i = 0; i < this.eles.length; i++) {
            //     var ele = this.eles[i];
            //     ele.textContent = con;
            // }
            this.each(function (ele) {
                ele.textContent = con;
            })
            return this;
        } else { //没有参数
            // 默认返回集合中的第一个(模拟jquery)
            return this.eles[0].textContent;
        }
    }
    GetEle.prototype.val = function (con) {
        if (arguments.length >= 1) {  // 有参数
            // for (var i = 0; i < this.eles.length; i++) {
            //     var ele = this.eles[i];
            //     ele.value = con;
            // }

            this.each(function (ele) {
                ele.value = con;
            })
            return this;
        } else { //没有参数
            // 默认返回集合中的第一个(模拟jquery)
            return this.eles[0].value;
        }
    }

    GetEle.prototype.hide = function () {
        // this ->指向调用此方法的实例化对象 {eles:[]}
        // for (var i = 0; i < this.eles.length; i++) {
        //     var ele = this.eles[i];
        //     ele.style.display = "none"
        // }
        this.each(function (ele) {
            ele.style.display = "none";
        })
        return this;
    }
    GetEle.prototype.show = function () {
        // this ->指向调用此方法的实例化对象 {eles:[]}
        // for (var i = 0; i < this.eles.length; i++) {
        //     var ele = this.eles[i];
        //     ele.style.display = "block";
        // }
        this.each(function (ele) {
            ele.style.display = "block";
        })
        return this;
    }

    // width()  获取和设置元素的宽度
    // width("200px")  => 有值,设置
    // width()         => 没有值,获取
    GetEle.prototype.width = function (con) {
        if (arguments.length >= 1) {
            this.each(function (ele) {

                // 200px pt em rem vw vh %    有单位  直接拼接
                // 200                        没有单位  => 默认px

                var unitReg = /^\d+(px|pt|em|rem|vw|vh|%)$/;
                if (unitReg.test(con)) {
                    ele.style.width = con;
                } else {
                    ele.style.width = con + "px";
                }

            })
            return this;
        } else {
            // 如果有多个 默认返回第一个
            // return this.eles[0].style.width;     // !!!!!!!!! style获取和设置内联样式

            // return parseFloat(getStyle(this.eles[0], "width"));

            return parseInt(this.getStyle("width"));

        }
    }

    // width()  获取和设置元素的宽度
    // width("200px")  => 有值,设置
    // width()         => 没有值,获取
    GetEle.prototype.height = function (con) {
        if (arguments.length >= 1) {
            this.each(function (ele) {

                // 200px pt em rem vw vh %    有单位  直接拼接
                // 200                        没有单位  => 默认px

                var unitReg = /^\d+(px|pt|em|rem|vw|vh|%)$/;
                if (unitReg.test(con)) {
                    ele.style.height = con;
                } else {
                    ele.style.height = con + "px";
                }

            })
            return this;
        } else {
            // 如果有多个 默认返回第一个
            // return this.eles[0].style.height;     // !!!!!!!!! style获取和设置内联样式

            // return parseFloat(getStyle(this.eles[0], "height"));

            return parseInt(this.getStyle("height"));

        }
    }


    // css()  获取和设置css样式
    // css("background","red") 有两个参数,就设置
    // css({"background":"red"}) 有一个对象参数,也是设置

    // css("background")       只有一个参数,就获取
    GetEle.prototype.css = function (key, val) {
        if (arguments.length >= 2) { // key, val
            this.each(function (ele) {
                ele.style[key] = val;
            })
            return this;
        } else if (arguments.length == 1) {  //key
            if (key instanceof Object) {
                //  {
                //     background: "red",
                //     width: "200px",
                //     height: "200px",
                //     float: "left",
                //     textAlign: "center",
                //     lineHeight: "100px",
                // }
                for (var name in key) {
                    console.log(name, key[name]);
                    // this.each(function (ele) {
                    //     ele.style[name] = key[name];
                    // })
                    this.css(name, key[name]);
                }
                return this;
            } else {
                return this.getStyle(key);
            }
        }
    }

    // attr()  获取和设置  属性节点 attribute
    // attr(key,val)   setAttribite(key,val) 有两个参数,就设置
    // attr(key)       getAttribite(key,val) 有一个参数,就获取
    GetEle.prototype.attr = function (key, val) {
        // this ->调用此方法的实例化对象 {eles:[]}
        // var key = arguments[0];
        // var val = arguments[1];
        if (arguments.length >= 2) {
            this.each(function (ele) {
                ele.setAttribute(key, val);
            })
            return this;

        } else if (arguments.length == 1) {
            return this.eles[0].getAttribute(key);
        }
    }
    // prop()  获取和设置元素节点的属性  ele.innerHTML ele.className
    // prop(key,val)      有两个参数,就设置
    // prop("className", "one")  Element.className = "one"

    // prop(key)        有一个参数,就获取
    // prop("className")  Element.className 

    GetEle.prototype.prop = function (key, val) {
        if (arguments.length >= 2) {
            this.each(function (ele) { // key, val
                ele[key] = val;
            })
            return this;
        } else if (arguments.length == 1) {  //key
            return this.eles[0][key];
        }
    }

    GetEle.prototype.addClass = function () {
        var _arg = arguments;
        this.each(function (ele) { // key, val
            ele.classList.add(..._arg);
        })
        return this;
    }

    GetEle.prototype.removeClass = function () {
        var _arg = arguments;
        this.each(function (ele) { // key, val
            ele.classList.remove(..._arg);
        })
        return this;
    }

    // 链式操作   方法的返回值 依然是一个实例化对象(对应构造函数)
    // var arr = [];
    // arr.concat(1, 2).concat(3, 4);

    // var str = "YY-MM-DD"
    // str.replace().replace.replace()

    // var p = new Promise(function () { })
    // p.then().then().then().catch()


    // eq(index)   => 返回对应下标的元素形成的实例化对象   {eles:[]}
    // $(".list li").eq(0).css({ background: "red" })  =>eq()之后想使用css方法(链式操作) 就意味着 eq()的返回值是一个GelEle实例化对象
    GetEle.prototype.eq = function (index) {
        // this.eles[index]
        var ele = this.eles[index]; //对应下标的元素

        // 以前实例化对象 {eles:[li*10]}

        this.eles = [ele];   // eles 存放元素的集合,单元素也要放到集合中

        return this;  // {eles:[li]}
    }

    // siblings()  返回除被选中元素以外 所有的同级元素(形成的实例化对象)
    // $(".list li").eq(0).siblings().css({ background: "blue" })
    GetEle.prototype.siblings = function () {
        var ele = this.eles[0]; // 被选中的元素

        var parentEle = ele.parentElement;  // 被选中的元素的父元素
        var children = parentEle.children; // 父元素中所有的子元素 (包含本身)

        // var arr = [];
        // for (var i = 0; i < children.length; i++) {
        //     var item = children[i];
        //     if (item !== ele) {
        //         arr.push(item);
        //     }
        // }

        var arr = Array.from(children).filter(item => item != ele);  // 除被选中元素以外 所有的同级元素
        this.eles = arr;

        return this;  // {eles:[]}
    }



    GetEle.prototype.click = function (fn) {
        // this ->指向调用此方法的实例化对象 {eles:[]}   
        // for (var i = 0; i < this.eles.length; i++) {
        //     var ele = this.eles[i];
        //     // ele.onclick = fn;
        //     ele.addEventListener("click", fn);
        // }

        this.each(function (ele) {
            ele.addEventListener("click", fn);
        })
        return this;
    }
    // 遍历实例化对象中的集合  每次循环时执行传入的回调函数 (item,index)
    GetEle.prototype.each = function (fn) {
        // this ->指向调用此方法的实例化对象 {eles:[]}   
        // 元素的集合  this.eles
        for (var i = 0; i < this.eles.length; i++) {
            var item = this.eles[i];
            var index = i;
            fn(item, index);

            // 注意 jquery中 第一个参数是下标,第二个才会循环的当前元素
            // fn(index, item);
        }
        return this;

    }
    GetEle.prototype.getStyle = function (attr) {
        var ele = this.eles[0]; // 默认返回集合中的第一个
        if (window.getComputedStyle) {
            return window.getComputedStyle(ele)[attr];
        } else {
            return ele.currentStyle[attr];
        }
    }


    // 获取非行内样式
    function getStyle(ele, attr) {
        if (window.getComputedStyle) {
            return window.getComputedStyle(ele)[attr];
        } else {
            return ele.currentStyle[attr];
        }
    }



    // 对GetEle进行二次封装  => 快速创建实例化对象并返回
    function $(selector) {
        return new GetEle(selector);
    }

    // $(".list li").html("a123123");
    // $("#title").html("hi");
    // $(".inp").val("haha");

    // $(".list li").click(function () {
    //     console.log(this);
    // })
    // $(".list li").click(function () {
    //     console.log(1111);
    // })


    $(".setHtml").click(function () {
        $(".list li").html("hello");
    })
    $(".getHtml").click(function () {
        alert($(".list li").html());
    })

    $(".hide").click(function () {
        $(".list li").hide();
    })
    $(".show").click(function () {
        $(".list li").show();
    })
    $(".setWidth").click(function () {
        // $(".list li").width("200px");
        $(".list li").width(200);
    })
    $(".getWidth").click(function () {
        // $(".list li").width("200px");
        alert($(".list li").width());
    })
    $(".css").click(function () {
        // $(".list li").width("200px");
        // $(".list li").css("background", "red");
        // console.log($(".list li").css("backgroundColor"));

        // $(".list li").css("background", "red");
        // $(".list li").css("width", "100px");
        // $(".list li").css("height", "100px");
        // $(".list li").css("float", "left");
        // $(".list li").css("text-align", "center");
        // $(".list li").css("line-height", "100px");

        $(".list li").css({
            background: "red",
            width: "100px",
            height: "100px",
            float: "left",
            textAlign: "center",
            lineHeight: "100px",
        })
    })

    $(".attr").click(function () {
        $(".list li").attr("asd", "123");
        $(".list li").attr("class", "one");

        console.log($(".list li").attr("asd"));
        console.log($(".list li").attr("class"));
    })
    $(".prop").click(function () {
        $(".list li").prop("id", "box");
        $(".list li").prop("className", "one");

        console.log($(".list li").prop("id"));
        console.log($(".list li").prop("className"));
    })

    $(".addClass").click(function () {
        $(".list li").addClass("one", "two", "three");
    })
    $(".removeClass").click(function () {
        $(".list li").removeClass("one", "three");
    })

    $(".eq").click(function () {
        console.log($(".list li").eq(0));
        $(".list li").eq(0).css({ background: "red" })
    })
    $(".siblings").click(function () {
        console.log($(".list li").eq(0).siblings());
        $(".list li").eq(0).siblings().css({ background: "blue" })
        // $(".list li").eq(0).css({ background: "red" }).siblings()
    })

    $(".chain").click(function () {
        $(".list li").eq(0).css({ background: "red" }).html("hello").width(200).addClass("active").siblings().css({ background: "blue" }).html("world").width(400).removeClass("active");
    })

</script>

</html>